﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq.Expressions;
using System.Xml;
using WebApiMIT3.Models;
using WebApiMIT3.Properties;


namespace WebApiMIT3.Utils
{
    public class XMLHandler
    {
        private const string FileName = "Model.xml";
        private const string Plugins = "Plugins";
        private const string Plugin = "Plugin";
        private const string Category = "Category";
        private const string Content = "Content";
        private const string ContentType = "ContentType";

        private const string RootXmlNode = "/Config";

        public static void SetConfig()
        {
            XmlReader xmlReader = XmlReader.Create(new StringReader(Properties.Resources.Config.ToString()));
            XmlNodeList nodeList = null;
            var xmlDoc = new XmlDocument();
            xmlDoc.Load(xmlReader);

            

            if (xmlDoc.DocumentElement != null)
            {
                nodeList = xmlDoc.DocumentElement.SelectNodes(RootXmlNode);
            }

            if (nodeList != null)
            {
                SetConfigValues(nodeList);
            }     
        }

        private static void SetConfigValues(XmlNodeList nodeList)
        {
            foreach (XmlNode node in nodeList)
            {
                Config.Database_IP = GetNodeStringValue(GetPropertyName(() => Config.Database_IP), node);
                Config.Database_Port = GetNodeStringValue(GetPropertyName(() => Config.Database_Port), node);
                Config.Database_Name = GetNodeStringValue(GetPropertyName(() => Config.Database_Name), node);
                Config.Database_Uid = GetNodeStringValue(GetPropertyName(() => Config.Database_Uid), node);
                Config.Database_Pass = GetNodeStringValue(GetPropertyName(() => Config.Database_Pass), node);

                Config.CategoryService_MinimumCheck = Convert.ToInt32(GetNodeStringValue(GetPropertyName(()=>Config.CategoryService_MinimumCheck),node));
            }
        }

        /// <summary>
        /// Get the categories for the CategoryModel.
        /// </summary>
        public static void GetCategoriesFromXML()
        {
            XmlReader xmlReader = XmlReader.Create(new StringReader(Properties.Resources.Categories.ToString()));
            var xmlDoc = new XmlDocument();
            xmlDoc.Load(xmlReader);

            foreach (XmlNode category in xmlDoc.ChildNodes[1])
            {
                var type = typeof(CategoryModel);
                var propertylist = type.GetProperties();
                foreach (var property in propertylist)
                {
                    var propertyName = property.Name;
                    var properyValue = property.PropertyType;
                    if (properyValue == new List<string>().GetType())
                    {
                        var childnode = category.SelectSingleNode(propertyName);
                        property.SetValue(type, GetNodeListStringValue(propertyName, childnode));
                    }
                }
            }
        }

        /// <summary>
        /// Unpacks the XML string to a list of datamodels.
        /// </summary>
        /// <param name="content">XMLstring</param>
        /// <returns>List of DataModels</returns>
        public static List<DataModel> UnpackModelFromXML(string content)
        {
            XmlReader xmlReader = XmlReader.Create(new StringReader(content));
            var xmlDoc = new XmlDocument();
            xmlDoc.Load(xmlReader);
            List<DataModel> dataModelList = new List<DataModel>();

            foreach (XmlNode plugin in xmlDoc.ChildNodes[1])
            {
                DataModel dataModel = new DataModel();
                var propertylist = dataModel.GetType().GetProperties();
                foreach (var property in propertylist)
                {
                    var propertyName = dataModel.GetType().GetProperty(property.Name).Name;
                    var modelProperty = dataModel.GetType().GetProperty(property.Name);
                    var propertyValue = dataModel.GetType().GetProperty(property.Name).PropertyType;
                    if (propertyValue == typeof(string))
                    {
                        modelProperty.SetValue(dataModel, GetNodeStringValue(propertyName, plugin));
                    }
                    else if (propertyValue == new List<string>().GetType())
                    {
                        var childnode = plugin.SelectSingleNode(propertyName);
                        modelProperty.SetValue(dataModel, GetNodeListStringValue(propertyName, childnode));
                    }
                }

                dataModelList.Add(dataModel);
            }

            return dataModelList;
        }

        // <Author>Rainer Schmitt</Author>
        // <StudentNo>1235656</StudentNo>
        // Copyright (c) 06/04/2015 All Right Reserved
        // <Date>06/04/2015</date>

        /// <summary>
        /// Packs the List of DataModels into a XML String.
        /// </summary>
        /// <param name="dataModelList">List of Datamodels</param>
        /// <returns>XML string</returns>
        public static string PackModelIntoXML(List<DataModel> dataModelList)
        {
            using (var stringWriter = new StringWriter())
            {
                using (var writer = XmlWriter.Create(stringWriter))
                {
                    writer.WriteStartDocument();
                    writer.WriteStartElement(Plugins);

                    foreach (var item in dataModelList)
                    {
                        writer.WriteStartElement(Plugin);

                        writer.WriteElementString(GetPropertyName(() => item.SourceName), item.SourceName);
                        writer.WriteElementString(GetPropertyName(() => item.SourceUrl), item.SourceUrl);
                        writer.WriteElementString(GetPropertyName(() => item.Author), item.Author);
                        writer.WriteElementString(GetPropertyName(() => item.Title), item.Title);
                        writer.WriteElementString(GetPropertyName(() => item.SummaryDescription), item.SummaryDescription);
                        writer.WriteElementString(GetPropertyName(() => item.FullDescription), item.FullDescription);
                        writer.WriteElementString(GetPropertyName(() => item.OriginalPublishDate), item.OriginalPublishDate);
                        writer.WriteElementString(GetPropertyName(() => item.UpdatePublishDate), item.UpdatePublishDate);
                        writer.WriteElementString(GetPropertyName(() => item.Enclosure), item.Enclosure);

                        // Multimedia
                        writer.WriteStartElement(GetPropertyName(() => item.MultiMedia));
                        foreach (var content in item.MultiMedia ?? new List<string>())
                        {
                            writer.WriteElementString(Content, content);
                        }

                        writer.WriteEndElement();

                        writer.WriteStartElement(GetPropertyName(() => item.Categories));
                        foreach (var category in item.Categories ?? new List<string>())
                        {
                            writer.WriteElementString(Category, category);
                        }

                        writer.WriteEndElement();

                        writer.WriteStartElement(GetPropertyName(() => item.Type));
                        foreach (var contentType in item.Type ?? new List<string>())
                        {
                            writer.WriteElementString(ContentType, contentType);
                        }

                        writer.WriteEndElement();

                        writer.WriteEndElement();
                    }

                    writer.WriteEndElement();
                    writer.WriteEndDocument();
                }

                return stringWriter.ToString();
            }
        }

        private static string GetPropertyName<T>(Expression<Func<T>> propertyExpression)
        {
            return (propertyExpression.Body as MemberExpression).Member.Name;
        }

        private static List<string> GetNodeListStringValue(string nodeName, XmlNode node)
        {
            if (!node.HasChildNodes)
            {
                return new List<string>();
            }

            var childNodes = node.ChildNodes;
            List<string> result = new List<string>();
            foreach (XmlNode childNode in childNodes)
            {
                result.Add(childNode.InnerText);
            }

            return result;
        }

        private static string GetNodeStringValue(string nodeName, XmlNode node)
        {
            var temp = node.SelectSingleNode(nodeName);
            return
                (temp != null)
                ? temp.InnerText
                : string.Empty;
        }
    }
}